# -*- CMake -*- master configuration file for building LAMMPS
########################################
# CMake build system
# This file is part of LAMMPS
cmake_minimum_required(VERSION 3.20)
########################################
# initialize version variables with project command
if(POLICY CMP0048)
  cmake_policy(SET CMP0048 NEW)
endif()
# set policy to silence warnings about ignoring <PackageName>_ROOT but use it
if(POLICY CMP0074)
  cmake_policy(SET CMP0074 NEW)
endif()
# set policy to silence warnings about ignoring  ${CMAKE_REQUIRED_LIBRARIES} but use it
if(POLICY CMP0075)
  cmake_policy(SET CMP0075 NEW)
endif()
# set policy to silence warnings about requiring execute permission for find_program
# we use OLD because the python-config script for the Fedora MinGW cross-compiler requires it currently
if(POLICY CMP0109)
  cmake_policy(SET CMP0109 OLD)
endif()
# set policy to silence warnings about timestamps of downloaded files. review occasionally if it may be set to NEW
if(POLICY CMP0135)
  cmake_policy(SET CMP0135 OLD)
endif()

########################################

project(lammps
        DESCRIPTION "The LAMMPS Molecular Dynamics Simulator"
        HOMEPAGE_URL "https://www.lammps.org"
        LANGUAGES CXX C)
set(SOVERSION 0)
get_property(BUILD_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)

include(GNUInstallDirs)
get_filename_component(LAMMPS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.. ABSOLUTE)
get_filename_component(LAMMPS_LIB_BINARY_DIR ${CMAKE_BINARY_DIR}/lib ABSOLUTE)
# collect all executables and shared libs in the top level build folder
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

set(LAMMPS_SOURCE_DIR     ${LAMMPS_DIR}/src)
set(LAMMPS_LIB_SOURCE_DIR ${LAMMPS_DIR}/lib)
set(LAMMPS_DOC_DIR        ${LAMMPS_DIR}/doc)
set(LAMMPS_TOOLS_DIR      ${LAMMPS_DIR}/tools)
set(LAMMPS_PYTHON_DIR     ${LAMMPS_DIR}/python)
set(LAMMPS_POTENTIALS_DIR ${LAMMPS_DIR}/potentials)
set(LAMMPS_THIRDPARTY_DIR ${LAMMPS_DIR}/third_party)

set(LAMMPS_DOWNLOADS_URL "https://download.lammps.org" CACHE STRING "Base URL for LAMMPS downloads")
set(LAMMPS_POTENTIALS_URL "${LAMMPS_DOWNLOADS_URL}/potentials")
set(LAMMPS_THIRDPARTY_URL "${LAMMPS_DOWNLOADS_URL}/thirdparty")
mark_as_advanced(LAMMPS_DOWNLOADS_URL)

find_package(Git)

# by default, install into $HOME/.local (not /usr/local), so that no root access (and sudo!!) is needed
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND (NOT CMAKE_CROSSCOMPILING))
    set(CMAKE_INSTALL_PREFIX "$ENV{USERPROFILE}/LAMMPS" CACHE PATH "Default install path" FORCE)
  else()
    set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "Default install path" FORCE)
  endif()
endif()

# If enabled, no need to use LD_LIBRARY_PATH / DYLD_LIBRARY_PATH when installed
option(LAMMPS_INSTALL_RPATH "Set runtime path for shared libraries linked to LAMMPS binaries" OFF)
if(LAMMPS_INSTALL_RPATH)
  set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR})
  set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON)
endif()

# Cmake modules/macros are in a subdirectory to keep this file cleaner
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules)

# make sure LIBRARY_PATH is set if environment variable is set
if(DEFINED ENV{LIBRARY_PATH})
  list(APPEND CMAKE_LIBRARY_PATH "$ENV{LIBRARY_PATH}")
  message(STATUS "Appending $ENV{LIBRARY_PATH} to CMAKE_LIBRARY_PATH: ${CMAKE_LIBRARY_PATH}")
endif()

include(LAMMPSUtils)

get_lammps_version(${LAMMPS_SOURCE_DIR}/version.h PROJECT_VERSION)

include(PreventInSourceBuilds)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CXX_FLAGS)
  set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CXX_FLAGS)
string(TOUPPER "${CMAKE_BUILD_TYPE}" BTYPE)

# check for files auto-generated by make-based buildsystem
# this is fast, so check for it all the time
check_for_autogen_files(${LAMMPS_SOURCE_DIR})

######################################################################
# compiler tests
# these need ot be done early (before further tests).
#####################################################################
include(CheckIncludeFileCXX)

# set required compiler flags and compiler/CPU arch specific optimizations
if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
  if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
    if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qrestrict")
    endif()
    if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /QxCOMMON-AVX512")
    else()
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /QxHost")
    endif()
  else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -restrict")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.3 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 17.4)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xCOMMON-AVX512")
    else()
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -xHost -fp-model fast=2 -no-prec-div -qoverride-limits -diag-disable=10441 -diag-disable=11074 -diag-disable=11076 -diag-disable=2196")
    endif()
  endif()
endif()

# silence excessive warnings for new Intel Compilers
if(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fp-model precise -Wno-tautological-constant-compare -Wno-unused-command-line-argument")
endif()

# silence excessive warnings for PGI/NVHPC compilers
if((CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC") OR (CMAKE_CXX_COMPILER_ID STREQUAL "PGI"))
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Minform=severe")
endif()

# silence nvcc warnings when using nvcc_wrapper
get_filename_component(LAMMPS_CXX_COMPILER_NAME "${CMAKE_CXX_COMPILER}" NAME CACHE)
if((PKG_KOKKOS) AND (Kokkos_ENABLE_CUDA) AND (LAMMPS_CXX_COMPILER_NAME STREQUAL "nvcc_wrapper"))
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xcudafe --diag_suppress=unrecognized_pragma,--diag_suppress=128,--diag_suppress=186")
endif()

# we *require* C++17 without extensions
# Kokkos also requires at least C++17 (currently)
if(NOT CMAKE_CXX_STANDARD)
# uncomment in case we plan to switch to C++20 as minimum standard
#  if(cxx_std_20 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
#    set(CMAKE_CXX_STANDARD 20)
#  else()
    set(CMAKE_CXX_STANDARD 17)
#  endif()
endif()
if(CMAKE_CXX_STANDARD LESS 17)
  message(FATAL_ERROR "C++ standard must be set to at least 17")
endif()
if(PKG_KOKKOS AND (CMAKE_CXX_STANDARD LESS 17))
  set(CMAKE_CXX_STANDARD 17)
endif()
# turn off C++20 check in lmptype.h
#if(LAMMPS_CXX17)
#  add_compile_definitions(LAMMPS_CXX17)
#endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Use compiler extensions")
# ugly hacks for MSVC which by default always reports an old C++ standard in the __cplusplus macro
# and prints lots of pointless warnings about "unsafe" functions
if(MSVC)
  if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Intel"))
    add_compile_options(/Zc:__cplusplus)
    add_compile_options(/wd4244)
    add_compile_options(/wd4267)
    add_compile_options(/wd4250)
    add_compile_options(/EHsc)
    add_compile_options(/utf-8)
  endif()
  add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()

# warn about potentially problematic GCC compiler versions
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  if (CMAKE_CXX_STANDARD GREATER_EQUAL 17)
    if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.3)
      message(WARNING "Using the GNU compilers version ${CMAKE_CXX_COMPILER_VERSION} with C++17 "
              "or later is not recommended. Please use GNU compilers version 9.3 or later")
    endif()
  endif()
endif()

# export all symbols when building a .dll file on windows
if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND BUILD_SHARED_LIBS)
  set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()

# do not include the (obsolete) MPI C++ bindings which makes for leaner object files
# and avoids namespace conflicts. Put this early to increase its visbility.
set(MPI_CXX_SKIP_MPICXX TRUE CACHE BOOL "Skip MPI C++ Bindings" FORCE)

########################################################################
# User input options                                                   #
########################################################################
# backward compatibility with older LAMMPS documentation
if (PYTHON_EXECUTABLE)
  set(Python_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()
# set path to python interpreter and thus enforcing python version when
# in a virtual environment and Python_EXECUTABLE is not set on command line
if(DEFINED ENV{VIRTUAL_ENV} AND NOT Python_EXECUTABLE)
  if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
    set(Python_EXECUTABLE "$ENV{VIRTUAL_ENV}/Scripts/python.exe")
  else()
    set(Python_EXECUTABLE "$ENV{VIRTUAL_ENV}/bin/python")
  endif()
  message(STATUS "Running in virtual environment: $ENV{VIRTUAL_ENV}\n"
    "   Setting Python interpreter to: ${Python_EXECUTABLE}")
endif()

find_package(Python COMPONENTS Interpreter QUIET)
# NOTE: RHEL 8.0 and Ubuntu 18.04LTS ship with Python 3.6, Python 3.8 was EOL in 2024
if(Python_VERSION VERSION_LESS 3.6)
  message(FATAL_ERROR "LAMMPS requires Python 3.6 or later")
endif()

set(LAMMPS_MACHINE "" CACHE STRING "Suffix to append to lmp binary (WON'T enable any features automatically")
mark_as_advanced(LAMMPS_MACHINE)
if(LAMMPS_MACHINE)
  set(LAMMPS_MACHINE "_${LAMMPS_MACHINE}")
endif()
set(LAMMPS_BINARY lmp${LAMMPS_MACHINE})

option(BUILD_SHARED_LIBS "Build shared library" OFF)
option(CMAKE_POSITION_INDEPENDENT_CODE "Create object compatible with shared libraries" ON)
option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF)
option(BUILD_LAMMPS_GUI "Build and install the LAMMPS GUI" OFF)

file(GLOB ALL_SOURCES CONFIGURE_DEPENDS ${LAMMPS_SOURCE_DIR}/[^.]*.cpp)
file(GLOB MAIN_SOURCES CONFIGURE_DEPENDS ${LAMMPS_SOURCE_DIR}/main.cpp)
list(REMOVE_ITEM ALL_SOURCES ${MAIN_SOURCES})
add_library(lammps ${ALL_SOURCES})

# add extra libraries for std::filesystem with older compilers
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.1)
  target_link_libraries(lammps PRIVATE stdc++fs)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
  target_link_libraries(lammps PRIVATE c++fs)
endif()

# tell CMake to export all symbols to a .dll on Windows with MinGW cross-compilers
if(BUILD_SHARED_LIBS AND (CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING)
  set_target_properties(lammps PROPERTIES LINK_FLAGS "-Wl,--export-all-symbols")
endif()

add_executable(lmp ${MAIN_SOURCES})
target_link_libraries(lmp PRIVATE lammps)
set_target_properties(lmp PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY})
# re-export all symbols for plugins
if(PKG_PLUGIN AND (NOT ((CMAKE_SYSTEM_NAME STREQUAL "Windows"))))
  set_target_properties(lmp PROPERTIES ENABLE_EXPORTS TRUE)
endif()
install(TARGETS lmp EXPORT LAMMPS_Targets DESTINATION ${CMAKE_INSTALL_BINDIR})

option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF)

set(STANDARD_PACKAGES
  ADIOS
  AMOEBA
  APIP
  ASPHERE
  BOCS
  BODY
  BPM
  BROWNIAN
  CG-DNA
  CG-SPICA
  CLASS2
  COLLOID
  COLVARS
  COMPRESS
  DIELECTRIC
  DIFFRACTION
  DIPOLE
  DPD-BASIC
  DPD-MESO
  DPD-REACT
  DPD-SMOOTH
  DRUDE
  EFF
  ELECTRODE
  EXTRA-COMMAND
  EXTRA-COMPUTE
  EXTRA-DUMP
  EXTRA-FIX
  EXTRA-MOLECULE
  EXTRA-PAIR
  FEP
  GRANULAR
  H5MD
  INTERLAYER
  KIM
  KSPACE
  LATBOLTZ
  LEPTON
  MACHDYN
  MANIFOLD
  MANYBODY
  MC
  MDI
  MEAM
  MESONT
  MGPT
  MISC
  ML-HDNNP
  ML-IAP
  ML-PACE
  ML-POD
  ML-QUIP
  ML-RANN
  ML-SNAP
  ML-UF3
  MOFFF
  MOLECULE
  MOLFILE
  NETCDF
  ORIENT
  PERI
  PHONON
  PLUGIN
  PLUMED
  PTM
  PYTHON
  QEQ
  QMMM
  QTB
  REACTION
  REAXFF
  REPLICA
  RHEO
  RIGID
  SCAFACOS
  SHOCK
  SMTBQ
  SPH
  SPIN
  SRD
  TALLY
  UEF
  VORONOI
  VTK
  YAFF)

set(SUFFIX_PACKAGES CORESHELL GPU KOKKOS OPT INTEL OPENMP)

foreach(PKG ${STANDARD_PACKAGES} ${SUFFIX_PACKAGES})
  option(PKG_${PKG} "Build ${PKG} Package" OFF)
endforeach()

######################################################
# packages with special compiler needs or external libs
######################################################
target_include_directories(lammps PUBLIC $<BUILD_INTERFACE:${LAMMPS_SOURCE_DIR}>)
target_include_directories(lammps PUBLIC $<BUILD_INTERFACE:${LAMMPS_THIRDPARTY_DIR}>)

if(PKG_ADIOS)
  # The search for ADIOS2 must come before MPI because
  # it includes its own MPI search with the latest FindMPI.cmake
  # script that defines the MPI::MPI_C target
  find_package(ADIOS2 REQUIRED)
  if(BUILD_MPI)
    if(NOT ADIOS2_HAVE_MPI)
      message(FATAL_ERROR "ADIOS2 must be built with MPI support when LAMMPS has MPI enabled")
    endif()
  else()
    if(ADIOS2_HAVE_MPI)
      message(FATAL_ERROR "ADIOS2 must be built without MPI support when LAMMPS has MPI disabled")
    endif()
  endif()
  target_link_libraries(lammps PRIVATE adios2::adios2)
endif()

if(NOT CMAKE_CROSSCOMPILING)
  find_package(MPI QUIET COMPONENTS CXX)
  option(BUILD_MPI "Build MPI version" ${MPI_FOUND})
else()
  option(BUILD_MPI "Build MPI version" OFF)
endif()

if(BUILD_MPI)
  # We use a non-standard procedure to cross-compile with MPI on Windows
  if((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING)
    include(MPI4WIN)
  else()
    find_package(MPI REQUIRED COMPONENTS CXX)
    option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF)
    if(LAMMPS_LONGLONG_TO_LONG)
      target_compile_definitions(lammps PRIVATE -DLAMMPS_LONGLONG_TO_LONG)
    endif()
  endif()
  target_link_libraries(lammps PUBLIC MPI::MPI_CXX)
else()
  target_sources(lammps PRIVATE ${LAMMPS_SOURCE_DIR}/STUBS/mpi.cpp)
  add_library(mpi_stubs INTERFACE)
  target_include_directories(mpi_stubs INTERFACE $<BUILD_INTERFACE:${LAMMPS_SOURCE_DIR}/STUBS>)
  target_link_libraries(lammps PUBLIC mpi_stubs)
endif()

set(LAMMPS_SIZES "smallbig" CACHE STRING "LAMMPS integer sizes (smallbig: 64-bit #atoms #timesteps, bigbig: also 64-bit imageint, 64-bit atom ids)")
set(LAMMPS_SIZES_VALUES smallbig bigbig)
set_property(CACHE LAMMPS_SIZES PROPERTY STRINGS ${LAMMPS_SIZES_VALUES})
validate_option(LAMMPS_SIZES LAMMPS_SIZES_VALUES)
string(TOUPPER ${LAMMPS_SIZES} LAMMPS_SIZES)
target_compile_definitions(lammps PUBLIC -DLAMMPS_${LAMMPS_SIZES})

# posix_memalign is not available on Windows
# with INTEL package and Intel compilers we use TBB's aligned malloc
if((CMAKE_SYSTEM_NAME STREQUAL "Windows")
   AND NOT (PKG_INTEL AND ((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") OR (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM"))))
  set(LAMMPS_MEMALIGN "0" CACHE STRING "posix_memalign() is not available on Windows" FORCE)
else()
  set(LAMMPS_MEMALIGN "64" CACHE STRING "enables the use of the posix_memalign() call instead of malloc() when large chunks or memory are allocated by LAMMPS. Set to 0 to disable")
endif()
if(NOT ${LAMMPS_MEMALIGN} STREQUAL "0")
  target_compile_definitions(lammps PRIVATE -DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN})
endif()

# this hack is required to compile fmt lib with CrayClang version 15.0.2
# CrayClang is only directly recognized by CMake version 3.28 and later
if(CMAKE_VERSION VERSION_LESS 3.28)
  get_filename_component(_exe "${CMAKE_CXX_COMPILER}" NAME)
  if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (_exe STREQUAL "crayCC"))
    target_compile_definitions(lammps PRIVATE -DFMT_STATIC_THOUSANDS_SEPARATOR)
  endif()
else()
  if(CMAKE_CXX_COMPILER_ID STREQUAL "CrayClang")
    target_compile_definitions(lammps PRIVATE -DFMT_STATIC_THOUSANDS_SEPARATOR)
  endif()
endif()

# "hard" dependencies between packages resulting
# in an error instead of skipping over files
pkg_depends(ML-IAP ML-SNAP)
pkg_depends(LATBOLTZ MPI)
pkg_depends(SCAFACOS MPI)
pkg_depends(AMOEBA KSPACE)
pkg_depends(DIELECTRIC KSPACE)
pkg_depends(DIELECTRIC EXTRA-PAIR)
pkg_depends(CG-DNA MOLECULE)
pkg_depends(CG-DNA ASPHERE)
pkg_depends(ELECTRODE KSPACE)
pkg_depends(EXTRA-MOLECULE MOLECULE)
pkg_depends(MESONT MOLECULE)
pkg_depends(RHEO BPM)
pkg_depends(APIP ML-PACE)

# detect if we may enable OpenMP support by default
set(BUILD_OMP_DEFAULT OFF)
find_package(OpenMP COMPONENTS CXX QUIET)
if(OpenMP_CXX_FOUND)
  check_omp_h_include()
  if(HAVE_OMP_H_INCLUDE)
    set(BUILD_OMP_DEFAULT ON)
  endif()
endif()

option(BUILD_OMP "Build with OpenMP support" ${BUILD_OMP_DEFAULT})

if(BUILD_OMP)
  find_package(OpenMP COMPONENTS CXX REQUIRED)
  check_omp_h_include()
  if(NOT HAVE_OMP_H_INCLUDE)
    message(FATAL_ERROR "Cannot find the 'omp.h' header file required for full OpenMP support")
  endif()

  if(((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 9.0)) OR
      (CMAKE_CXX_COMPILER_ID STREQUAL "PGI") OR (CMAKE_CXX_COMPILER_ID STREQUAL "NVHPC") OR
      (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") OR (CMAKE_CXX_COMPILER_ID STREQUAL "XLClang") OR
      ((CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)) OR
      ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)) OR
      ((CMAKE_CXX_COMPILER_ID STREQUAL "CrayClang") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0)) OR
      ((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0)))
    # GCC 9.x and later plus Clang 10.x and later implement strict OpenMP 4.0 semantics for consts.
    # Intel 18.0 was tested to support both, so we switch to OpenMP 4+ from 19.x onward to be safe.
    set(LAMMPS_OMP_COMPAT_LEVEL 4)
  else()
    set(LAMMPS_OMP_COMPAT_LEVEL 3)
  endif()
  target_compile_definitions(lammps PRIVATE -DLAMMPS_OMP_COMPAT=${LAMMPS_OMP_COMPAT_LEVEL})
  target_link_libraries(lammps PRIVATE OpenMP::OpenMP_CXX)
  target_link_libraries(lmp PRIVATE OpenMP::OpenMP_CXX)

  # this hack is required to correctly link with OpenMP support when using CrayClang version 15.0.2
  # CrayClang is only directly recognized by version 3.28 and later
  if(CMAKE_VERSION VERSION_LESS 3.28)
    get_filename_component(_exe "${CMAKE_CXX_COMPILER}" NAME)
    if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (_exe STREQUAL "crayCC"))
      set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fopenmp")
      set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -fopenmp")
    endif()
  else()
    if(CMAKE_CXX_COMPILER_ID STREQUAL "CrayClang")
      set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fopenmp")
      set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} -fopenmp")
    endif()
  endif()
endif()

# lower C++ standard for fmtlib sources when using Intel classic compiler
if((CMAKE_CXX_COMPILER_ID STREQUAL "Intel") AND (CMAKE_CXX_STANDARD GREATER_EQUAL 17)
    AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2021.10))
  message(STATUS "Lowering C++ standard for compiling fmtlib sources with Intel Classic compiler")
  get_filename_component(LMP_UTILS_SRC "${LAMMPS_SOURCE_DIR}/utils.cpp" ABSOLUTE)
  get_filename_component(LMP_VARIABLE_SRC "${LAMMPS_SOURCE_DIR}/variable.cpp" ABSOLUTE)
  get_filename_component(FMT_FORMAT_SRC "${LAMMPS_SOURCE_DIR}/fmtlib_format.cpp" ABSOLUTE)
  get_filename_component(FMT_OS_SRC "${LAMMPS_SOURCE_DIR}/fmtlib_os.cpp" ABSOLUTE)
  set_source_files_properties("${FMT_FORMAT_SRC}" "${FMT_OS_SRC}" "${LMP_VARIABLE_SRC}" "${LMP_UTILS_SRC}"
          PROPERTIES COMPILE_OPTIONS "-std=c++14")
endif()

option(USE_INTERNAL_LINALG "Prefer internal library with BLAS/LAPACK subset over system BLAS/LAPACK" OFF)
if(PKG_ML-QUIP OR PKG_ML-POD OR PKG_ELECTRODE OR PKG_RHEO OR BUILD_TOOLS)
  if(NOT USE_INTERNAL_LINALG)
    find_package(LAPACK)
    find_package(BLAS)
  endif()
  if((NOT LAPACK_FOUND) OR (NOT BLAS_FOUND) OR USE_INTERNAL_LINALG)
    set(USE_INTERNAL_LINALG ON)
    file(GLOB LINALG_SOURCES CONFIGURE_DEPENDS ${LAMMPS_LIB_SOURCE_DIR}/linalg/[^.]*.cpp)
    add_library(linalg STATIC ${LINALG_SOURCES})
    set_target_properties(linalg PROPERTIES OUTPUT_NAME lammps_linalg${LAMMPS_MACHINE})
    set(BLAS_LIBRARIES "$<TARGET_FILE:linalg>")
    set(LAPACK_LIBRARIES "$<TARGET_FILE:linalg>")
    target_link_libraries(lammps PRIVATE linalg)
  else()
    list(APPEND LAPACK_LIBRARIES ${BLAS_LIBRARIES})
  endif()
endif()

# tweak jpeg library names to avoid linker errors with MinGW cross-compilation
set(JPEG_NAMES libjpeg libjpeg-62)
find_package(JPEG QUIET)
option(WITH_JPEG "Enable JPEG support" ${JPEG_FOUND})
if(WITH_JPEG)
  find_package(JPEG REQUIRED)
  target_compile_definitions(lammps PRIVATE -DLAMMPS_JPEG)
  target_link_libraries(lammps PRIVATE JPEG::JPEG)
endif()

find_package(PNG QUIET)
find_package(ZLIB QUIET)
if(PNG_FOUND AND ZLIB_FOUND)
  option(WITH_PNG "Enable PNG support" ON)
else()
  option(WITH_PNG "Enable PNG support" OFF)
endif()
if(WITH_PNG)
  find_package(PNG REQUIRED)
  find_package(ZLIB REQUIRED)
  target_link_libraries(lammps PRIVATE PNG::PNG ZLIB::ZLIB)
  target_compile_definitions(lammps PRIVATE -DLAMMPS_PNG)
endif()

find_program(GZIP_EXECUTABLE gzip)
find_package_handle_standard_args(GZIP REQUIRED_VARS GZIP_EXECUTABLE)
option(WITH_GZIP "Enable GZIP support" ${GZIP_FOUND})
if(WITH_GZIP)
  if(GZIP_FOUND OR ((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING))
    target_compile_definitions(lammps PRIVATE -DLAMMPS_GZIP)
  else()
    message(FATAL_ERROR "gzip executable not found")
  endif()
endif()

find_program(FFMPEG_EXECUTABLE ffmpeg)
find_package_handle_standard_args(FFMPEG REQUIRED_VARS FFMPEG_EXECUTABLE)
option(WITH_FFMPEG "Enable FFMPEG support" ${FFMPEG_FOUND})
if(WITH_FFMPEG)
  if(FFMPEG_FOUND OR ((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING))
    target_compile_definitions(lammps PRIVATE -DLAMMPS_FFMPEG)
  else()
    message(FATAL_ERROR "ffmpeg executable not found")
  endif()
endif()

if(BUILD_SHARED_LIBS)
  set(CONFIGURE_REQUEST_PIC "--with-pic")
  set(CMAKE_REQUEST_PIC "-DCMAKE_POSITION_INDEPENDENT_CODE=${CMAKE_POSITION_INDEPENDENT_CODE}")
  set(CUDA_REQUEST_PIC "-Xcompiler ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}")
else()
  set(CONFIGURE_REQUEST_PIC)
  set(CMAKE_REQUEST_PIC)
  set(CUDA_REQUEST_PIC)
endif()

foreach(PKG_WITH_INCL KSPACE PYTHON ML-IAP VORONOI COLVARS ML-HDNNP MDI MOLFILE NETCDF
        PLUMED QMMM ML-QUIP SCAFACOS MACHDYN VTK KIM COMPRESS ML-PACE LEPTON EXTRA-COMMAND)
  if(PKG_${PKG_WITH_INCL})
    include(Packages/${PKG_WITH_INCL})
  endif()
endforeach()

# settings for misc packages and styles
if(PKG_MISC)
  option(LAMMPS_ASYNC_IMD "Asynchronous IMD processing" OFF)
  mark_as_advanced(LAMMPS_ASYNC_IMD)
  if(LAMMPS_ASYNC_IMD)
    target_compile_definitions(lammps PRIVATE -DLAMMPS_ASYNC_IMD)
    message(STATUS "Using IMD in asynchronous mode")
  endif()
endif()

# optionally enable building script wrappers using swig
option(WITH_SWIG "Build scripting language wrappers with SWIG" OFF)
if(WITH_SWIG)
  get_filename_component(LAMMPS_SWIG_DIR ${LAMMPS_SOURCE_DIR}/../tools/swig ABSOLUTE)
  add_subdirectory(${LAMMPS_SWIG_DIR} swig)
endif()

########################################################################
# make the standard math library overrideable and autodetected (for systems that don't have it)
find_library(STANDARD_MATH_LIB m DOC "Standard Math library")
mark_as_advanced(STANDARD_MATH_LIB)
if(STANDARD_MATH_LIB)
  target_link_libraries(lammps PRIVATE ${STANDARD_MATH_LIB})
endif()

######################################
# Generate Basic Style files
######################################
include(StyleHeaderUtils)
RegisterStyles(${LAMMPS_SOURCE_DIR})

########################################################
# Fetch missing external files and archives for packages
########################################################
option(DOWNLOAD_POTENTIALS "Automatically download large potential files" ON)
mark_as_advanced(DOWNLOAD_POTENTIALS)
foreach(PKG ${STANDARD_PACKAGES} ${SUFFIX_PACKAGES})
  if(PKG_${PKG})
    FetchPotentials(${LAMMPS_SOURCE_DIR}/${PKG} ${LAMMPS_POTENTIALS_DIR})
  endif()
endforeach()

##############################################
# add sources of enabled packages
############################################
foreach(PKG ${STANDARD_PACKAGES})
  set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG})

  file(GLOB ${PKG}_SOURCES CONFIGURE_DEPENDS ${${PKG}_SOURCES_DIR}/[^.]*.cpp)
  file(GLOB ${PKG}_HEADERS CONFIGURE_DEPENDS ${${PKG}_SOURCES_DIR}/[^.]*.h)

  # check for package files in src directory due to old make system
  DetectBuildSystemConflict(${LAMMPS_SOURCE_DIR} ${${PKG}_SOURCES} ${${PKG}_HEADERS})

  if(PKG_${PKG})
    # detects styles in package and adds them to global list
    RegisterStyles(${${PKG}_SOURCES_DIR})

    target_sources(lammps PRIVATE ${${PKG}_SOURCES})
    target_include_directories(lammps PRIVATE ${${PKG}_SOURCES_DIR})
  endif()

  RegisterPackages(${${PKG}_SOURCES_DIR})
endforeach()

# dedicated check for entire contents of accelerator packages
foreach(PKG ${SUFFIX_PACKAGES})
  set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG})

  file(GLOB ${PKG}_SOURCES CONFIGURE_DEPENDS ${${PKG}_SOURCES_DIR}/[^.]*.cpp)
  file(GLOB ${PKG}_HEADERS CONFIGURE_DEPENDS ${${PKG}_SOURCES_DIR}/[^.]*.h)

  # check for package files in src directory due to old make system
  DetectBuildSystemConflict(${LAMMPS_SOURCE_DIR} ${${PKG}_SOURCES} ${${PKG}_HEADERS})

  RegisterPackages(${${PKG}_SOURCES_DIR})
endforeach()

##############################################
# add lib sources of (simple) enabled packages
############################################
foreach(PKG_LIB H5MD)
  if(PKG_${PKG_LIB})
    string(TOLOWER "${PKG_LIB}" PKG_LIB)
    file(GLOB_RECURSE ${PKG_LIB}_SOURCES CONFIGURE_DEPENDS
      ${LAMMPS_LIB_SOURCE_DIR}/${PKG_LIB}/[^.]*.c ${LAMMPS_LIB_SOURCE_DIR}/${PKG_LIB}/[^.]*.cpp)
    add_library(${PKG_LIB} STATIC ${${PKG_LIB}_SOURCES})
    set_target_properties(${PKG_LIB} PROPERTIES OUTPUT_NAME lammps_${PKG_LIB}${LAMMPS_MACHINE})
    target_link_libraries(lammps PRIVATE ${PKG_LIB})
    if(PKG_LIB STREQUAL "h5md")
      target_include_directories(h5md PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/h5md/include ${HDF5_INCLUDE_DIRS})
    else()
      target_include_directories(${PKG_LIB} PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/${PKG_LIB})
    endif()
  endif()
endforeach()

if(PKG_ELECTRODE OR PKG_ML-POD)
  target_link_libraries(lammps PRIVATE ${LAPACK_LIBRARIES})
endif()

if(PKG_H5MD)
  include(Packages/H5MD)
endif()

######################################################################
# packages which selectively include variants based on enabled styles
# e.g. accelerator packages
######################################################################
foreach(PKG_WITH_INCL CORESHELL DPD-BASIC DPD-SMOOTH MC MISC PHONON QEQ OPENMP KOKKOS OPT INTEL GPU)
  if(PKG_${PKG_WITH_INCL})
    include(Packages/${PKG_WITH_INCL})
  endif()
endforeach()

if(PKG_PLUGIN)
  target_compile_definitions(lammps PRIVATE -DLMP_PLUGIN)
endif()

# link with -ldl or equivalent for plugin loading; except on Windows
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
   target_link_libraries(lammps PRIVATE ${CMAKE_DL_LIBS})
endif()

######################################################################
# the windows version of LAMMPS requires a couple extra libraries
# and the MPI library - if use - has to be linked right before those
# and after everything else that is compiled locally
######################################################################
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  target_link_libraries(lammps PRIVATE "wsock32;psapi")
endif()

######################################################
# Generate style headers based on global list of
# styles registered during package selection
# Generate packages headers from all packages
######################################################
set(LAMMPS_STYLE_HEADERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/styles)

GenerateStyleHeaders(${LAMMPS_STYLE_HEADERS_DIR})
GeneratePackagesHeaders(${LAMMPS_STYLE_HEADERS_DIR})

target_include_directories(lammps PRIVATE ${LAMMPS_STYLE_HEADERS_DIR})

######################################
# Generate lmpinstalledpkgs.h
######################################
set(temp "#ifndef LMP_INSTALLED_PKGS_H\n#define LMP_INSTALLED_PKGS_H\n")
set(temp "${temp}const char * LAMMPS_NS::LAMMPS::installed_packages[] =  {\n")
set(temp_PKG_LIST ${STANDARD_PACKAGES} ${SUFFIX_PACKAGES})
list(SORT temp_PKG_LIST)
foreach(PKG ${temp_PKG_LIST})
    if(PKG_${PKG})
        set(temp "${temp}  \"${PKG}\",\n")
    endif()
endforeach()
set(temp "${temp}  NULL\n};\n#endif\n\n")
message(STATUS "Generating lmpinstalledpkgs.h...")
file(WRITE "${LAMMPS_STYLE_HEADERS_DIR}/lmpinstalledpkgs.h.tmp" "${temp}" )
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${LAMMPS_STYLE_HEADERS_DIR}/lmpinstalledpkgs.h.tmp" "${LAMMPS_STYLE_HEADERS_DIR}/lmpinstalledpkgs.h")

######################################
# Generate lmpgitversion.h
######################################
add_custom_target(gitversion COMMAND ${CMAKE_COMMAND}
  -DLAMMPS_DIR="${LAMMPS_DIR}"
  -DGIT_EXECUTABLE="${GIT_EXECUTABLE}"
  -DGIT_FOUND="${GIT_FOUND}"
  -DLAMMPS_STYLE_HEADERS_DIR="${LAMMPS_STYLE_HEADERS_DIR}"
  -P ${CMAKE_CURRENT_SOURCE_DIR}/Modules/generate_lmpgitversion.cmake)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${LAMMPS_STYLE_HEADERS_DIR}/gitversion.h)
add_dependencies(lammps gitversion)

###########################################
# Actually add executable and lib to build
############################################
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
list(FIND LANGUAGES "Fortran" _index)
if(_index GREATER -1)
  target_link_libraries(lammps PRIVATE ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES})
endif()
set(LAMMPS_CXX_HEADERS angle.h atom.h bond.h citeme.h comm.h command.h compute.h dihedral.h domain.h
  error.h exceptions.h fix.h force.h group.h improper.h input.h info.h json.h json_fwd.h kspace.h
  lammps.h lattice.h library.h lmppython.h lmptype.h memory.h modify.h neighbor.h neigh_list.h
  output.h pair.h platform.h pointers.h region.h timer.h universe.h update.h utils.h variable.h)
set(LAMMPS_FMT_HEADERS core.h format.h)
set(LAMMPS_JSON_HEADERS json_fwd.hpp json.hpp)

set_target_properties(lammps PROPERTIES OUTPUT_NAME lammps${LAMMPS_MACHINE})
set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION})
set_target_properties(lammps PROPERTIES PREFIX "lib")
target_include_directories(lammps PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/fmt ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/nlohmann)
foreach(_HEADER ${LAMMPS_CXX_HEADERS})
  add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/${_HEADER} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_SOURCE_DIR}/${_HEADER} ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/${_HEADER} DEPENDS ${LAMMPS_SOURCE_DIR}/${_HEADER})
  add_custom_target(${_HEADER} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/${_HEADER})
  add_dependencies(lammps ${_HEADER})
  if(BUILD_SHARED_LIBS)
    install(FILES ${LAMMPS_SOURCE_DIR}/${_HEADER} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps)
  endif()
endforeach()
foreach(_HEADER ${LAMMPS_FMT_HEADERS})
  add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/fmt/${_HEADER} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_SOURCE_DIR}/fmt/${_HEADER} ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/fmt/${_HEADER} DEPENDS ${LAMMPS_SOURCE_DIR}/fmt/${_HEADER})
  add_custom_target(fmt_${_HEADER} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/fmt/${_HEADER})
  add_dependencies(lammps fmt_${_HEADER})
  if(BUILD_SHARED_LIBS)
    install(FILES ${LAMMPS_SOURCE_DIR}/fmt/${_HEADER} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps/fmt)
  endif()
endforeach()
foreach(_HEADER ${LAMMPS_JSON_HEADERS})
  add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/nlohmann/${_HEADER} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LAMMPS_SOURCE_DIR}/nlohmann/${_HEADER} ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/nlohmann/${_HEADER} DEPENDS ${LAMMPS_SOURCE_DIR}/nlohmann/${_HEADER})
  add_custom_target(json_${_HEADER} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/includes/lammps/nlohmann/${_HEADER})
  add_dependencies(lammps json_${_HEADER})
  if(BUILD_SHARED_LIBS)
    install(FILES ${LAMMPS_SOURCE_DIR}/nlohmann/${_HEADER} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps/nlohmann)
  endif()
endforeach()
target_include_directories(lammps INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/includes>)
add_library(LAMMPS::lammps ALIAS lammps)
get_target_property(LAMMPS_DEFINES lammps INTERFACE_COMPILE_DEFINITIONS)
set(LAMMPS_API_DEFINES)
foreach(_DEF ${LAMMPS_DEFINES})
  set(LAMMPS_API_DEFINES "${LAMMPS_API_DEFINES} -D${_DEF}")
endforeach()
if(BUILD_SHARED_LIBS)
  install(TARGETS lammps EXPORT LAMMPS_Targets
          LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
          ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
          RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
  if(NOT BUILD_MPI)
    install(TARGETS mpi_stubs EXPORT LAMMPS_Targets
            LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
            ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
            RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
  endif()
  configure_file(pkgconfig/liblammps.pc.in ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_MACHINE}.pc @ONLY)
  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_MACHINE}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
  install(EXPORT LAMMPS_Targets FILE LAMMPS_Targets.cmake NAMESPACE LAMMPS:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/LAMMPS)
  include(CMakePackageConfigHelpers)
  configure_file(LAMMPSConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfig.cmake" @ONLY)
  write_basic_package_version_file("LAMMPSConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY ExactVersion)
  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfigVersion.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/LAMMPS)
endif()
install(FILES ${LAMMPS_DOC_DIR}/lammps.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME ${LAMMPS_BINARY}.1)

include(Tools)
include(Documentation)

###############################################################################
# Install bench, potential and force field files in data directory
###############################################################################
set(LAMMPS_INSTALL_DATADIR ${CMAKE_INSTALL_DATADIR}/lammps)

install(DIRECTORY ${LAMMPS_DIR}/bench DESTINATION ${LAMMPS_INSTALL_DATADIR})
install(DIRECTORY ${LAMMPS_POTENTIALS_DIR} DESTINATION ${LAMMPS_INSTALL_DATADIR})
if(BUILD_TOOLS)
  install(DIRECTORY ${LAMMPS_TOOLS_DIR}/msi2lmp/frc_files DESTINATION ${LAMMPS_INSTALL_DATADIR})
endif()

configure_file(etc/profile.d/lammps.sh.in ${CMAKE_BINARY_DIR}/etc/profile.d/lammps.sh @ONLY)
configure_file(etc/profile.d/lammps.csh.in ${CMAKE_BINARY_DIR}/etc/profile.d/lammps.csh @ONLY)
install(
  FILES ${CMAKE_BINARY_DIR}/etc/profile.d/lammps.sh
        ${CMAKE_BINARY_DIR}/etc/profile.d/lammps.csh
  DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/profile.d
)

###############################################################################
# Install LAMMPS lib and python module into site-packages folder with
# "install-python" target.  Behaves exactly like "make install-python" for
# conventional build.  Only available, if a shared library is built.
# This is primarily for people that only want to use the Python wrapper.
###############################################################################
if(BUILD_SHARED_LIBS)
  # backward compatibility
  find_package(Python COMPONENTS Interpreter)
  if(BUILD_IS_MULTI_CONFIG)
    set(MY_BUILD_DIR ${CMAKE_BINARY_DIR}/$<CONFIG>)
  else()
    set(MY_BUILD_DIR ${CMAKE_BINARY_DIR})
  endif()
  set(LIBLAMMPS_SHARED_BINARY ${MY_BUILD_DIR}/liblammps${LAMMPS_MACHINE}${CMAKE_SHARED_LIBRARY_SUFFIX})
  if(Python_EXECUTABLE)
    add_custom_target(
      install-python ${Python_EXECUTABLE} ${LAMMPS_PYTHON_DIR}/install.py -p ${LAMMPS_PYTHON_DIR}/lammps
      -l ${LIBLAMMPS_SHARED_BINARY} -w ${MY_BUILD_DIR} -v ${LAMMPS_SOURCE_DIR}/version.h
      COMMENT "Installing LAMMPS Python module")
  else()
    add_custom_target(
      install-python
      ${CMAKE_COMMAND} -E echo "Must have Python installed to install the LAMMPS Python module")
  endif()
else()
  add_custom_target(
    install-python
    ${CMAKE_COMMAND} -E echo "Must build LAMMPS as a shared library to use the Python module")
endif()

include(Testing)
include(CodeCoverage)
include(CodingStandard)
find_package(ClangFormat 11.0 QUIET)

if(ClangFormat_FOUND)
  add_custom_target(format-src
    COMMAND ${ClangFormat_EXECUTABLE} --verbose -i -style=file *.cpp *.h */*.cpp */*.h
    WORKING_DIRECTORY ${LAMMPS_SOURCE_DIR})
endif()

# extract Kokkos compilation settings
get_cmake_property(_allvars VARIABLES)
foreach(_var ${_allvars})
  if(${_var})
    string(REGEX MATCH "Kokkos_ENABLE_(SERIAL|THREADS|OPENMP|CUDA|HIP|SYCL|OPENMPTARGET|HPX)" _match ${_var})
    if(_match)
      string(REGEX REPLACE "Kokkos_ENABLE_(OPENMP|SERIAL|CUDA|HIP|SYCL)" "\\1" _match ${_var})
      list(APPEND KOKKOS_DEVICE ${_match})
    endif()
    string(REGEX MATCH "Kokkos_ARCH" _match ${_var})
    if(_match)
      string(REGEX REPLACE "Kokkos_ARCH_(.*)" "\\1" _match ${_var})
      list(APPEND KOKKOS_ARCH ${_match})
    endif()
  endif()
endforeach()

get_target_property(DEFINES lammps COMPILE_DEFINITIONS)
if(BUILD_IS_MULTI_CONFIG)
  set(LAMMPS_BUILD_TYPE "Multi-Config")
else()
  set(LAMMPS_BUILD_TYPE ${CMAKE_BUILD_TYPE})
endif()
include(FeatureSummary)
feature_summary(DESCRIPTION "The following tools and libraries have been found and configured:" WHAT PACKAGES_FOUND)
if(GIT_FOUND AND EXISTS ${LAMMPS_DIR}/.git)
  execute_process(COMMAND ${GIT_EXECUTABLE} describe --dirty=-modified --always
    OUTPUT_VARIABLE GIT_DESCRIBE
    ERROR_QUIET
    WORKING_DIRECTORY ${LAMMPS_DIR}
    OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
message(STATUS "<<< Build configuration >>>
   LAMMPS Version:   ${PROJECT_VERSION} ${GIT_DESCRIBE}
   Operating System: ${CMAKE_SYSTEM_NAME} ${CMAKE_LINUX_DISTRO} ${CMAKE_DISTRO_VERSION}
   CMake Version:    ${CMAKE_VERSION}
   Build type:       ${LAMMPS_BUILD_TYPE}
   Install path:     ${CMAKE_INSTALL_PREFIX}
   Generator:        ${CMAKE_GENERATOR} using ${CMAKE_MAKE_PROGRAM}")
if(CMAKE_CROSSCOMPILING)
  message(STATUS "Cross compiling on ${CMAKE_HOST_SYSTEM}")
endif()
###############################################################################
# Print package summary
###############################################################################
set(ENABLED_PACKAGES)
foreach(PKG ${STANDARD_PACKAGES} ${SUFFIX_PACKAGES})
  if(PKG_${PKG})
    list(APPEND ENABLED_PACKAGES ${PKG})
  endif()
endforeach()
if(ENABLED_PACKAGES)
  list(SORT ENABLED_PACKAGES)
else()
  set(ENABLED_PACKAGES "<None>")
endif()
message(STATUS "Enabled packages: ${ENABLED_PACKAGES}")

message(STATUS "<<< Compilers and Flags: >>>
-- C++ Compiler:     ${CMAKE_CXX_COMPILER}
      Type:          ${CMAKE_CXX_COMPILER_ID}
      Version:       ${CMAKE_CXX_COMPILER_VERSION}
      C++ Standard:  ${CMAKE_CXX_STANDARD}
      C++ Flags:    ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTYPE}}
      Defines:       ${DEFINES}")
if(CMAKE_CXX_COMPILER_LAUNCHER)
  message(STATUS "      Launcher:      ${CMAKE_CXX_COMPILER_LAUNCHER}")
endif()
get_target_property(OPTIONS lammps COMPILE_OPTIONS)
if(OPTIONS)
  message("      Options:       ${OPTIONS}")
endif()
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
list(FIND LANGUAGES "Fortran" _index)
if(_index GREATER -1)
  message(STATUS "Fortran Compiler: ${CMAKE_Fortran_COMPILER}
      Type:          ${CMAKE_Fortran_COMPILER_ID}
      Version:       ${CMAKE_Fortran_COMPILER_VERSION}
      Fortran Flags:${CMAKE_Fortran_FLAGS} ${CMAKE_Fortran_FLAGS_${BTYPE}}")
endif()
list(FIND LANGUAGES "C" _index)
if(_index GREATER -1)
  message(STATUS "C compiler:       ${CMAKE_C_COMPILER}
      Type:          ${CMAKE_C_COMPILER_ID}
      Version:       ${CMAKE_C_COMPILER_VERSION}
      C Flags:      ${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BTYPE}}")
  if(CMAKE_C_COMPILER_LAUNCHER)
    message(STATUS "      Launcher:      ${CMAKE_C_COMPILER_LAUNCHER}")
  endif()
endif()
message(STATUS "<<< Linker flags: >>>")
message(STATUS "Executable name:  ${LAMMPS_BINARY}")
get_target_property(OPTIONS lammps LINK_OPTIONS)
if(OPTIONS)
  message(STATUS "Linker options:   ${OPTIONS}")
endif()
if(CMAKE_EXE_LINKER_FLAGS)
  message(STATUS "Executable linker flags: ${CMAKE_EXE_LINKER_FLAGS}")
endif()
if(BUILD_SHARED_LIBS)
  message(STATUS "Shared library flags:    ${CMAKE_SHARED_LINKER_FLAGS}")
else()
  message(STATUS "Static library flags:    ${CMAKE_STATIC_LINKER_FLAGS}")
endif()
if(BUILD_MPI)
  message(STATUS "<<< MPI flags >>>
-- MPI_defines:      ${MPI_CXX_COMPILE_DEFINITIONS}
-- MPI includes:     ${MPI_CXX_INCLUDE_PATH}
-- MPI libraries:    ${MPI_CXX_LIBRARIES};${MPI_Fortran_LIBRARIES}")
endif()
if(PKG_GPU)
  message(STATUS "<<< GPU package settings >>>
-- GPU API:                  ${GPU_API}")
  if(GPU_API STREQUAL "CUDA")
    message(STATUS "CUDA Compiler:            ${CUDA_NVCC_EXECUTABLE}")
    message(STATUS "GPU default architecture: ${GPU_ARCH}")
    message(STATUS "GPU binning with CUDPP:   ${CUDPP_OPT}")
    message(STATUS "CUDA MPS support:         ${CUDA_MPS_SUPPORT}")
  elseif(GPU_API STREQUAL "HIP")
    message(STATUS "HIP platform:     ${HIP_PLATFORM}")
    message(STATUS "HIP architecture: ${HIP_ARCH}")
    if(HIP_USE_DEVICE_SORT)
      message(STATUS "HIP GPU sorting: on")
    else()
      message(STATUS "HIP GPU sorting: off")
    endif()
  endif()
  message(STATUS "GPU precision:            ${GPU_PREC}")
endif()
if(PKG_KOKKOS)
  message(STATUS "Kokkos Devices: ${KOKKOS_DEVICE}")
  if(KOKKOS_ARCH)
    message(STATUS "Kokkos Architecture: ${KOKKOS_ARCH}")
  endif()
endif()
if(PKG_KSPACE)
  if (FFT_USE_HEFFTE)
    message(STATUS "<<< FFT settings >>>
-- Primary FFT lib:  heFFTe")
    if (FFT_HEFFTE_BACKEND)
      message(STATUS "heFFTe backend:  ${FFT_HEFFTE_BACKEND}")
    else()
      message(STATUS "heFFTe backend:  stock (builtin FFT implementation, tested for corrected but not optimized for production)")
    endif()
    message(STATUS "Using distributed FFT algorithms from heFTTe")
    if(FFT_SINGLE)
      message(STATUS "Using single precision FFTs")
    else()
      message(STATUS "Using double precision FFTs")
    endif()
  else()
    message(STATUS "<<< FFT settings >>>
-- Primary FFT lib:  ${FFT}")
    if(FFT_SINGLE)
      message(STATUS "Using single precision FFTs")
    else()
      message(STATUS "Using double precision FFTs")
    endif()
    if(FFT_FFTW_THREADS OR FFT_MKL_THREADS)
      message(STATUS "Using threaded FFTs")
    else()
      message(STATUS "Using non-threaded FFTs")
    endif()
    message(STATUS "Using builtin distributed FFT algorithms")
  endif()
  if(PKG_KOKKOS)
    message(STATUS "Kokkos FFT: ${FFT_KOKKOS}")
  endif()
endif()
if(BUILD_DOC)
  message(STATUS "<<< Building HTML Manual >>>")
endif()
if(BUILD_TOOLS)
  message(STATUS "<<< Building Tools >>>")
endif()
if(BUILD_LAMMPS_GUI)
  message(STATUS "<<< Building LAMMPS-GUI >>>")
  if(LAMMPS_GUI_USE_PLUGIN)
    message(STATUS "Loading LAMMPS library as plugin at run time")
  else()
    message(STATUS "Linking LAMMPS library at compile time")
  endif()
  if(BUILD_WHAM)
    message(STATUS "<<< Building WHAM >>>")
  endif()
endif()
if(ENABLE_TESTING)
  message(STATUS "<<< Building Unit Tests >>>")
  if(ENABLE_COVERAGE)
    message(STATUS "Collecting code coverage data")
  endif()
endif()
